#include "sceneview.h"
#include "scenenode.h"
#include "scene.h"
#include <gtkglmm.h>
#include <gtkglmm.h>
#include <GL/gl.h>
#include <GL/glu.h>

namespace moogle
{
  scene_view::scene_view(const Glib::RefPtr<const Gdk::GL::Config>& config, scene* scene)
    : Gtk::GL::DrawingArea(config), _scene(scene)
  {
  }

  scene_view::~scene_view()
  {
  }

  void scene_view::on_realize()
  {
    // We need to call the base on_realize()
    Gtk::GL::DrawingArea::on_realize();

    Glib::RefPtr<Gdk::GL::Window> glwindow = get_gl_window();

    // BEGIN OpenGL
    if (!glwindow->gl_begin(get_gl_context()))
      return;

    GLUquadricObj* qobj = gluNewQuadric();
    gluQuadricDrawStyle(qobj, GLU_FILL);
    glNewList(1, GL_COMPILE);
    gluSphere(qobj, 1.0, 20, 20);
    glEndList();

    const static GLfloat light_diffuse[] = {1.0, 0.0, 0.0, 1.0};
    const static GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0};
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_DEPTH_TEST);

    glClearColor(0.0, 0.0, 1.0, 1.0);
    glClearDepth(1.0);

    glViewport(0, 0, get_width(), get_height());

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(40.0, 1.0, 1.0, 10.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 3.0,
              0.0, 0.0, 0.0,
              0.0, 1.0, 0.0);
    glTranslatef(0.0, 0.0, -3.0);

    glwindow->gl_end();
    // END OpenGL
  }

  bool scene_view::on_configure_event(GdkEventConfigure*)
  {
    Glib::RefPtr<Gdk::GL::Window> glwindow = get_gl_window();

    // BEGIN OpenGL
    if (!glwindow->gl_begin(get_gl_context()))
      return false;

    glViewport(0, 0, get_width(), get_height());

    glwindow->gl_end();
    // END OpenGL

    return true;
  }

  bool scene_view::on_expose_event(GdkEventExpose*)
  {
    Glib::RefPtr<Gdk::GL::Window> glwindow = get_gl_window();

    // BEGIN OpenGL
    if (!glwindow->gl_begin(get_gl_context()))
      return false;

    render();

    // Swap buffers.
    if (glwindow->is_double_buffered())
      glwindow->swap_buffers();
    else
      glFlush();

    glwindow->gl_end();
    // END OpenGL

    return true;
  }

  scene* scene_view::get_scene()
  { return _scene; }
  
  void scene_view::set_scene(scene* scene)
  { _scene = scene; }

  static void render_r(scene_node* node)
  {
    for (auto it = node->children().begin(); it != node->children().end(); ++it)
      render_r(*it);

    node->render();
  }

  void scene_view::render()
  {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glCallList(1);
    render_r(get_scene()->root());
  }
}
